package edu.umd.ion.wavemeter.client;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox; 
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.widgetideas.client.ProgressBar;

import edu.umd.ion.wavemeter.service.CalibrationResult;
import edu.umd.ion.wavemeter.service.CalibrationSettings;
import edu.umd.ion.wavemeter.service.InterlockSettings;
import edu.umd.ion.wavemeter.service.WavemeterChannelData;
import edu.umd.ion.wavemeter.service.WavemeterParameters;
import edu.umd.ion.wavemeter.service.WavemeterServiceAsync;

public class WavemeterChannelWidget extends WavemeterSimpleChannelWidget {
	private CheckBox ActiveCheck, ExposureModeCheck;
	private TextBox ExposureValue, Exposure2Value;
	private HasKeyboardFocus ExposureFocus = new HasKeyboardFocus();
	private HasKeyboardFocus Exposure2Focus = new HasKeyboardFocus();
	private String ChannelName;
	private ChannelPIDWidget PIDWidget;
	private ProgressBar RelBar=new ProgressBar(0,4096,0), 
						AbsBar=new ProgressBar(-6,0,0), 
						RelBar2=new ProgressBar(0,4096,0),
						AbsBar2=new ProgressBar(-6,0,0),
						AvgBar=new ProgressBar(0,3000,0),
						AvgBar2=new ProgressBar(0,3000,0);
	private DisclosurePanel everything;
	private CheckBox InterlockEnable;
	private InterlockSettings MyInterlockSettings = new InterlockSettings(0,0,0);
	TextBox MinWavelengthBox, MaxWavelengthBox, CalibrationWavelengthBox;
	private CalibrationConfirmationDialog CalDialog; 
	private CalibrationSettings MyCalibrationSettings;
	private static int NumPIDChannels = -1;
		
	private ProgressBar.TextFormatter dBTextFormatter = new  ProgressBar.TextFormatter() {
		protected String getText(ProgressBar bar, double curProgress)
		{
			return NumberFormat.getFormat("0.0").format(10*curProgress)+" dB";
		}
	};
	
	private ClickHandler InitiateCalibration = new ClickHandler() {
		public void onClick(ClickEvent event) {
			CalDialog.center();
			CalDialog.show();
		}		
	};
	
	private ClickHandler DoCalibration = new ClickHandler() {
		public void onClick(ClickEvent event) {
			double CalibrationWavelength = Double.parseDouble(CalibrationWavelengthBox.getText());
			WavemeterService.calibrate(WavemeterParameters.cReturnWavelengthVac, 
					CalibrationWavelength, ChannelNumber, CalibrationCallback);
		}		
	};
	
	private AsyncCallback<Void> CommandCallback = new AsyncCallback<Void>() {
		public void onFailure(Throwable caught) {
			try {
				//ErrorLabel.setHTML("Command: " + caught.getMessage());
				throw caught;
			} catch (IncompatibleRemoteServiceException e) {
				// this client is not compatible with the server; cleanup and refresh the 
				// browser
			} catch (Throwable e) {
				// last resort -- a very unexpected exception
			}	
		}

		public void onSuccess(Void result) {
			//ErrorLabel.setHTML("");
		}
	};

	private AsyncCallback<CalibrationResult> CalibrationCallback = new AsyncCallback<CalibrationResult>() {
		public void onFailure(Throwable caught) {
			try {
				//ErrorLabel.setHTML("Command: " + caught.getMessage());
				throw caught;
			} catch (IncompatibleRemoteServiceException e) {
				// this client is not compatible with the server; cleanup and refresh the 
				// browser
			} catch (Throwable e) {
				// last resort -- a very unexpected exception
			}	
		}

		public void onSuccess(CalibrationResult result) {
			//ErrorLabel.setHTML("");
		}
	};

	private AsyncCallback<CalibrationSettings> CalibrationSettingsCallback = new AsyncCallback<CalibrationSettings>() {
		public void onFailure(Throwable caught) {
			try {
				//ErrorLabel.setHTML("Command: " + caught.getMessage());
				throw caught;
			} catch (IncompatibleRemoteServiceException e) {
				// this client is not compatible with the server; cleanup and refresh the 
				// browser
			} catch (Throwable e) {
				// last resort -- a very unexpected exception
			}			
		}

		public void onSuccess(CalibrationSettings result) {
			MyCalibrationSettings = result;
			CalibrationWavelengthBox.setText( String.valueOf(result.CalibrationWavelength) );
		}
	};
	
	private AsyncCallback<InterlockSettings> InterlockCallback = new AsyncCallback<InterlockSettings>() {
		public void onFailure(Throwable caught) {
			try {
				//ErrorLabel.setHTML("Command: " + caught.getMessage());
				throw caught;
			} catch (IncompatibleRemoteServiceException e) {
				// this client is not compatible with the server; cleanup and refresh the 
				// browser
			} catch (Throwable e) {
				// last resort -- a very unexpected exception
			}			
		}

		public void onSuccess(InterlockSettings result) {
			MyInterlockSettings = result;
			MinWavelengthBox.setText( String.valueOf(MyInterlockSettings.MinWavelength));
			MaxWavelengthBox.setText( String.valueOf(MyInterlockSettings.MaxWavelength));
			InterlockEnable.setValue(MyInterlockSettings.Enable);
		}
	};
	
	private AsyncCallback<Integer> NumPIDChannelsCallback = new AsyncCallback<Integer>() {
		public void onFailure(Throwable caught) {			
		}
		public void onSuccess(Integer myNumPIDChannels) {
			NumPIDChannels = myNumPIDChannels;
			PIDWidget.setVisible(ChannelNumber<NumPIDChannels);
		}
	};
	
	ClickHandler PushInterlockSettings = new ClickHandler() {
		public void onClick(ClickEvent e) {
			MyInterlockSettings.Channel = ChannelNumber;
			MyInterlockSettings.Enable = InterlockEnable.getValue();
			MyInterlockSettings.MinWavelength = Double.parseDouble(MinWavelengthBox.getText());
			MyInterlockSettings.MaxWavelength = Double.parseDouble(MaxWavelengthBox.getText());
			WavemeterService.setInterlock(MyInterlockSettings, CommandCallback);
		}
	};
	
	OpenHandler<DisclosurePanel> MyDisclosureHandler = new OpenHandler<DisclosurePanel>()
	{
		public void onOpen(OpenEvent<DisclosurePanel> event) {
			WavemeterService.getInterlock(ChannelNumber, InterlockCallback);
			WavemeterService.getCalibrationSettings(ChannelNumber, CalibrationSettingsCallback);
		}
	};

	public void setPIDVisible(boolean visible)
	{
		PIDWidget.setVisible(visible);
	}
	
	public void set(WavemeterChannelData data)
	{
		super.set(data);
		ActiveCheck.setValue(data.active);
		if (Active) {
			if (data.InterlockEnabled) {
				if (data.InterlockInRange) {
					setWavelengthLabelColor(inRangeColor);
				} else {
					setWavelengthLabelColor(outOfRangeColor);
				}
			} else {
				setWavelengthLabelColor(activeColor);
			} 
		} else {
			setWavelengthLabelColor(inactiveColor);
		} 
		if (!ExposureFocus.isFocused()) {
			ExposureValue.setText(String.valueOf(data.Exposure1));
		}
		if (!Exposure2Focus.isFocused()) {
			Exposure2Value.setText(String.valueOf(data.Exposure2));
		}
		ExposureModeCheck.setValue(data.AutoExposure);
		InterlockEnable.setValue(data.InterlockEnabled);
		PIDWidget.set(data);
		if (data.Avg1>0)
		{
			RelBar.setProgress(data.Max1);
			AbsBar.setProgress(Math.log(data.Max1/4096./data.Exposure1)/Math.log(10));
			RelBar2.setProgress(data.Max2);
			AbsBar2.setProgress(Math.log(data.Max2/4096./(data.Exposure1+data.Exposure2))/Math.log(10));
			AvgBar.setProgress(data.Avg1);
			AvgBar2.setProgress(data.Avg2);
		}
		if (MyInterlockSettings.Serial<data.InterlockSettingsSerial) {
			WavemeterService.getInterlock(ChannelNumber, InterlockCallback);
		}
	}
	
	public void setExposure1()
	{
		WavemeterService.setExposure( ChannelNumber, 1, Integer.parseInt(ExposureValue.getText()), CommandCallback );
	}

	public void setExposure2()
	{
		WavemeterService.setExposure( ChannelNumber, 2, Integer.parseInt(Exposure2Value.getText()), CommandCallback );
	}
	
	public WavemeterChannelWidget(WavemeterServiceAsync service, int Number, String Name, boolean showunit, Panel errorPanel)
	{
		super(service,Number,showunit,errorPanel);
		ChannelName = Name;
		CalDialog = new CalibrationConfirmationDialog(DoCalibration);
	}
	
	public void initialize(com.google.gwt.xml.client.Element domelement) {
		// Inside Out Details
		ExposureModeCheck = new CheckBox("AutoExposure");
		ExposureModeCheck.addClickHandler(new ClickHandler() {
	      	public void onClick(ClickEvent e) {
	      		boolean checked = ExposureModeCheck.getValue();
	      		WavemeterService.setExposureMode(ChannelNumber, checked, CommandCallback);
	      }
	    });

		ExposureValue = new TextBox();
		ExposureValue.setMaxLength(3);
		ExposureValue.setVisibleLength(4);
		ExposureValue.addKeyPressHandler(new KeyoardOnlyDigits(new ClickHandler(){
			public void onClick(ClickEvent e) { setExposure1(); }
		}) );
		ExposureValue.addFocusHandler(ExposureFocus);
		ExposureValue.addBlurHandler(ExposureFocus);

		Exposure2Value = new TextBox();
		Exposure2Value.setMaxLength(3);
		Exposure2Value.setVisibleLength(4);
		Exposure2Value.addKeyPressHandler(new KeyoardOnlyDigits(new ClickHandler(){
			public void onClick(ClickEvent e) { setExposure2(); }
		}) );
		Exposure2Value.addFocusHandler(Exposure2Focus);
		Exposure2Value.addBlurHandler(Exposure2Focus);

		HorizontalPanel tmp = new HorizontalPanel();
		tmp.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
		tmp.setSpacing(0);
		Label tmplabel = new Label("Exposure");
		tmplabel.setWidth("5em");
		tmp.add(tmplabel);
		tmp.add(ExposureValue);
		tmp.add(Exposure2Value);
		tmp.add(UnitBox);
		
		VerticalPanel Details = new VerticalPanel();
		HorizontalPanel Details1 = new HorizontalPanel();
		Details1.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
		Details1.add(ExposureModeCheck);
		Details1.add(tmp);
		Details1.setStyleName("layout-ChannelDetails");

		HorizontalPanel IntensityBars = new HorizontalPanel();
		AbsBar.setTextFormatter(dBTextFormatter);
		RelBar.setTitle("Maximum Exposure Interferometers");
		IntensityBars.add( RelBar );
		AvgBar.setTitle("Average Exposure Interferometers");
		IntensityBars.add( AvgBar );
		AbsBar.setTitle("Maximum Absolute Exposure Interferometers");		
		IntensityBars.add( AbsBar );		
		IntensityBars.setWidth("100%");

		HorizontalPanel IntensityBars2 = new HorizontalPanel();
		AbsBar2.setTextFormatter(dBTextFormatter);
		RelBar2.setTitle("Maximum Exposure Wide Interferometer");
		IntensityBars2.add( RelBar2 );
		AvgBar2.setTitle("Average Exposure Wide Interferometer");
		IntensityBars2.add( AvgBar2 );
		AbsBar2.setTitle("Maximum Absolute Exposure Wide Interferometer");		
		IntensityBars2.add( AbsBar2 );
		IntensityBars2.setWidth("100%");
		
		HorizontalPanel InterlockPanel = new HorizontalPanel();
		InterlockEnable = new CheckBox("Enable Interlock");
		InterlockEnable.addClickHandler(this.PushInterlockSettings);
		InterlockPanel.add( InterlockEnable );
		MinWavelengthBox = new TextBox();
		MinWavelengthBox.setStylePrimaryName("gwt-TextBox-PID");
		MinWavelengthBox.setWidth("150px");
		MinWavelengthBox.addKeyPressHandler(new KeyoardOnlyDigits(this.PushInterlockSettings) );
		InterlockPanel.add( new Label("Min Wavelength"));
		InterlockPanel.add(MinWavelengthBox);
		MaxWavelengthBox = new TextBox();
		MaxWavelengthBox.setStylePrimaryName("gwt-TextBox-PID");
		MaxWavelengthBox.addKeyPressHandler(new KeyoardOnlyDigits(this.PushInterlockSettings) );
		MaxWavelengthBox.setWidth("150px");
		InterlockPanel.add( new Label("Max Wavelength"));
		InterlockPanel.add(MaxWavelengthBox);
		CalibrationWavelengthBox = new TextBox();
		CalibrationWavelengthBox.setStylePrimaryName("gwt-TextBox-PID");
		CalibrationWavelengthBox.addKeyPressHandler(new KeyoardOnlyDigits( new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				MyCalibrationSettings.CalibrationWavelength = Double.valueOf(CalibrationWavelengthBox.getText());
				WavemeterService.setCalibrationSettings(ChannelNumber, MyCalibrationSettings, CommandCallback);
				CalibrationWavelengthBox.setText(String.valueOf(MyCalibrationSettings.CalibrationWavelength));
			}		
		}));
		CalibrationWavelengthBox.setWidth("150px");
		InterlockPanel.add( new Label("Calibration Wavelength"));
		InterlockPanel.add(CalibrationWavelengthBox);
		InterlockPanel.add( new Button("Calibrate", InitiateCalibration) );
		
		Details.add( Details1 );
		Details.add( IntensityBars );
		Details.add( IntensityBars2 );
		Details.add( InterlockPanel );
		Details.setWidth("100%");
		
		DisclosurePanel DetailsDisc = new DisclosurePanel("Details");
	    DetailsDisc.setContent(Details);
	    DetailsDisc.setStyleName("layout-ChannelDetails");
	    DetailsDisc.setWidth("100%");
	    DetailsDisc.addOpenHandler(MyDisclosureHandler);
		
		// Vertical Panel
	    HorizontalPanel ActivitiesPanel = new HorizontalPanel(); 
	    
		ActiveCheck = new CheckBox("Active");
		ActiveCheck.addClickHandler(new ClickHandler() {
		      	public void onClick(ClickEvent e) {
		      		boolean checked = ActiveCheck.getValue();
		      		WavemeterService.addChannelName(ChannelNumber, ChannelName, CommandCallback);
		      		WavemeterService.setActive(ChannelNumber, checked, CommandCallback);
		      }
		    });

		ActivitiesPanel.add(ActiveCheck);
		   
		VerticalPanel vert = new VerticalPanel();
		vert.setHorizontalAlignment(VerticalPanel.ALIGN_LEFT);
		vert.add(ActivitiesPanel);
	    vert.add(WavelengthLabel);
	    vert.add(ErrorLabel);
	    vert.add( DetailsDisc);
	    vert.add( PIDWidget = new ChannelPIDWidget(WavemeterService,ChannelNumber,ErrorPanel) );
	    vert.setStyleName("layout-ChannelVertWidget");
	    if (NumPIDChannels<0) {
	    	WavemeterService.getNumberOfPIDChannels(NumPIDChannelsCallback);
	    } else {
	    	PIDWidget.setVisible(ChannelNumber<NumPIDChannels);
	    }
		everything = new DisclosurePanel(ChannelName.length()>0 ? ChannelName : "Channel "+String.valueOf(ChannelNumber+1));
	    everything.setContent(vert);
	    everything.setStyleName("layout-ChannelWidget");
	    everything.setWidth("100%");

	    if (domelement.hasAttribute("showpid"))
		{
			setPIDVisible( Integer.parseInt(domelement.getAttribute("showpid"))==1 );
		}
	    WavemeterService.addChannelName(ChannelNumber, ChannelName, CommandCallback);
	    initWidget(everything);
	}
	
	
	
  	public int getChannelNumber() {
		return ChannelNumber;
	}
}
